// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_BASE_LIST_CONTAINER_HELPER_H_
#define CC_BASE_LIST_CONTAINER_HELPER_H_

#include <stddef.h>

#include <memory>

#include "base/macros.h"
#include "cc/base/cc_export.h"

namespace cc {

// Helper class for ListContainer non-templated logic. All methods are private,
// and only exposed to friend classes.
// For usage, see comments in ListContainer (list_container.h).
class CC_EXPORT ListContainerHelper final {
private:
    template <typename T>
    friend class ListContainer;

    template <typename T>
    friend class RandomAccessListContainer;

    explicit ListContainerHelper(size_t max_size_for_derived_class);
    ListContainerHelper(size_t max_size_for_derived_class,
        size_t num_of_elements_to_reserve_for);
    ~ListContainerHelper();

    // This class deals only with char* and void*. It does allocation and passing
    // out raw pointers, as well as memory deallocation when being destroyed.
    class CharAllocator;

    // This class points to a certain position inside memory of
    // CharAllocator. It is a base class for ListContainer iterators.
    struct CC_EXPORT PositionInCharAllocator {
        CharAllocator* ptr_to_container;
        size_t vector_index;
        char* item_iterator;

        PositionInCharAllocator(const PositionInCharAllocator& other);

        PositionInCharAllocator(CharAllocator* container,
            size_t vector_ind,
            char* item_iter);

        bool operator==(const PositionInCharAllocator& other) const;
        bool operator!=(const PositionInCharAllocator& other) const;

        PositionInCharAllocator Increment();
        PositionInCharAllocator ReverseIncrement();
    };

    // Iterator classes that can be used to access data.
    /////////////////////////////////////////////////////////////////
    class CC_EXPORT Iterator : public PositionInCharAllocator {
        // This class is only defined to forward iterate through
        // CharAllocator.
    public:
        Iterator(CharAllocator* container,
            size_t vector_ind,
            char* item_iter,
            size_t index);
        ~Iterator();

        size_t index() const;

    protected:
        // This is used to track how many increment has happened since begin(). It
        // is used to avoid double increment at places an index reference is
        // needed. For iterator this means begin() corresponds to index 0 and end()
        // corresponds to index |size|.
        size_t index_;
    };

    class CC_EXPORT ConstIterator : public PositionInCharAllocator {
        // This class is only defined to forward iterate through
        // CharAllocator.
    public:
        ConstIterator(CharAllocator* container,
            size_t vector_ind,
            char* item_iter,
            size_t index);
        ConstIterator(const Iterator& other); // NOLINT
        ~ConstIterator();

        size_t index() const;

    protected:
        // This is used to track how many increment has happened since begin(). It
        // is used to avoid double increment at places an index reference is
        // needed. For iterator this means begin() corresponds to index 0 and end()
        // corresponds to index |size|.
        size_t index_;
    };

    class CC_EXPORT ReverseIterator : public PositionInCharAllocator {
        // This class is only defined to reverse iterate through
        // CharAllocator.
    public:
        ReverseIterator(CharAllocator* container,
            size_t vector_ind,
            char* item_iter,
            size_t index);
        ~ReverseIterator();

        size_t index() const;

    protected:
        // This is used to track how many increment has happened since rbegin(). It
        // is used to avoid double increment at places an index reference is
        // needed. For reverse iterator this means rbegin() corresponds to index 0
        // and rend() corresponds to index |size|.
        size_t index_;
    };

    class CC_EXPORT ConstReverseIterator : public PositionInCharAllocator {
        // This class is only defined to reverse iterate through
        // CharAllocator.
    public:
        ConstReverseIterator(CharAllocator* container,
            size_t vector_ind,
            char* item_iter,
            size_t index);
        ConstReverseIterator(const ReverseIterator& other); // NOLINT
        ~ConstReverseIterator();

        size_t index() const;

    protected:
        // This is used to track how many increment has happened since rbegin(). It
        // is used to avoid double increment at places an index reference is
        // needed. For reverse iterator this means rbegin() corresponds to index 0
        // and rend() corresponds to index |size|.
        size_t index_;
    };

    // Unlike the ListContainer methods, these do not invoke element destructors.
    void RemoveLast();
    void EraseAndInvalidateAllPointers(Iterator* position);
    void InsertBeforeAndInvalidateAllPointers(Iterator* position,
        size_t number_of_elements);

    ConstReverseIterator crbegin() const;
    ConstReverseIterator crend() const;
    ReverseIterator rbegin();
    ReverseIterator rend();
    ConstIterator cbegin() const;
    ConstIterator cend() const;
    Iterator begin();
    Iterator end();

    Iterator IteratorAt(size_t index);
    ConstIterator IteratorAt(size_t index) const;

    size_t size() const;
    bool empty() const;

    size_t MaxSizeForDerivedClass() const;

    size_t GetCapacityInBytes() const;

    // Unlike the ListContainer method, this one does not invoke element
    // destructors.
    void clear();

    size_t AvailableSizeWithoutAnotherAllocationForTesting() const;

    // Hands out memory location for an element at the end of data structure.
    void* Allocate(size_t size_of_actual_element_in_bytes);

    std::unique_ptr<CharAllocator> data_;

    DISALLOW_COPY_AND_ASSIGN(ListContainerHelper);
};

} // namespace cc

#endif // CC_BASE_LIST_CONTAINER_HELPER_H_
